package service.autoconfigure;

import hello.HelloService;
import org.springframework.boot.autoconfigure.condition.*;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.boot.env.PropertiesPropertySourceLoader;
import org.springframework.context.annotation.*;
import org.springframework.core.env.PropertySource;
import org.springframework.core.env.*;
import org.springframework.core.type.AnnotatedTypeMetadata;
import org.springframework.stereotype.Component;

/**
 * 自动配置类。
 * <p>
 * 关于spring boot对properties文件加载实现的源码，可以查阅 {@link PropertiesPropertySourceLoader#load} 方法。<br/>
 * spring boot在启动时，会把application.properties或application.yml的配置文件解释为属性源{@link PropertySource},并添加到{@link ConfigurableEnvironment}对象。
 * </p>
 * <p>
 * {@link EnableConfigurationProperties}注解的作用是，把指定的类注册为Bean；
 * 同时注册一个Bean后置处理器ConfigurationPropertiesBindingPostProcessor，检查带了{@link ConfigurationProperties}注解的Bean，从属性源中读取属性值，并绑定到Bean的相应成员属性中。
 * </p>
 *
 * @author sai
 * @see PropertiesPropertySourceLoader
 * @see Environment
 * @see ConfigurableEnvironment
 * @see MutablePropertySources
 * @see PropertySourcesPropertyResolver
 * @since 2020/10/7
 */
@ConditionalOnClass(HelloService.class)
@EnableConfigurationProperties(ContentProperties.class)
public class ServiceAutoConfiguration {

    // @formatter:off
    @Bean
    @ConditionalOnMissingBean
    @ConditionalOnValidDgutContent
    HelloService helloService(ContentProperties properties) {
        return new HelloService() {
            @Override
            public void sayHello(String name) {
                System.out.println(name.concat("老师，").concat(properties.getContent()));
            }
        };
    }
    // @formatter:on

    /**
     * 自定义一个{@link Condition}
     * <p>{@link Condition}可以通过{@link Conditional}注解，决定一个{@link Component}、{@link Configuration}、{@link Bean}是否能注册到Spring容器。</p>
     */
    static class CustomCondition extends SpringBootCondition {

        @Override
        public ConditionOutcome getMatchOutcome(ConditionContext context, AnnotatedTypeMetadata metadata) {

            Environment env = context.getEnvironment();

            ConditionMessage.Builder condition =
                    ConditionMessage.forCondition("检查dgut.content");

            if (env.containsProperty("dgut.content")) {
                String value = env.getProperty("dgut.content");
                assert value != null;
                if (value.contains("企业级")) {
                    return ConditionOutcome.match(
                            condition.available(String.format(" dgut.content 不为null，并且包含 ('%s') 字符串", value)));
                }
                return ConditionOutcome.noMatch(
                        condition.because(String.format(" dgut.content 不包含 ('%s') 字符串", value)));

            }

            return ConditionOutcome.noMatch(
                    condition.didNotFind("property").items("'dgut.content'"));
        }
    }

}